#pragma once

#include "../shared/shared_types.h"
#include "Singleton.h"
#include <list>

namespace Putin{

/*!
 * \brief Input argument. All that is needed. 
 */
struct InputArg{
	int x;
	int y;
	char key;
};

/*!
 * \brief Just a silly class to get around some template issues
 */
class InputFunctorBase
{
public:
	virtual ~InputFunctorBase() {};

	/*!
	 * \brief
	 * Write brief comment for operator () here.
	 * \param arg The input data passed on
	 * \returns a boolean state
	 */
	virtual void operator()(InputArg arg)=0;
};


/*!
 * \brief
 * A function wrapper for a member function
 * 
 * \param T
 * Object class that implements the wrapped function
 */
template <typename T>
class InputFunctor : public InputFunctorBase
{
public:
	// A simple shorthand for a generic member function taking a InputArg
	typedef void(T::*Function)(InputArg);
	
	InputFunctor(Function f,T* o)
	{
		mFunction = f;
		mObject = o;
	}

	/*!
	 * \brief A wrapper class for some function taking InputArg
	 * 
	 * This function wrapper will prob. be used to capture 
	 * callbacks within classes to input handling.
	 * 
	 * \param arg The input data passed on
	 * 
	 * \returns Simply passes on the bool return state of its wrapped function
	 */
	void operator()(InputArg arg)
	{
		return (mObject->*mFunction)(arg);
	}

private:
	Function	mFunction;
	T*			mObject;
};

/*!
 * \brief
 * A global input manager for keyboard and mouse
 */
class InputManager : public Singleton<InputManager>
{
public:

	InputManager();
	virtual ~InputManager();

	bool init();
	bool terminate();

	bool update();

	bool isKeyDown(unsigned char key);

	Vec2i getMousePos();

	void addKeyboardCallback(InputFunctorBase* func);
	void addMouseClickCallback(InputFunctorBase* func);
	void addMouseMoveCallback(InputFunctorBase* func);

private:
	
	std::list<InputFunctorBase*>	mKeyboardCallbacks;
	std::list<InputFunctorBase*>	mMouseClickCallbacks;
	std::list<InputFunctorBase*>	mMouseMoveCallbacks;

	bool mRunning;

	unsigned char mKeyBuffer[256];
	int	mMouseX;
	int mMouseY;
};


}
